From 084b3e366ef3df61ad5285d60d38448fe1310122 Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Wed, 27 Apr 2005 14:04:44 +0000 Subject: [PATCH] bitkeeper revision 1.1327.2.9 (426f9bfcIjY9QAFCPqWBbFw35vclow) Add support for unix-domain sockets on xend. Remove some dead code. Signed-off-by: Mike Wray --- .rootkeys | 8 - tools/python/xen/web/SrvBase.py | 1 - tools/python/xen/web/SrvDir.py | 2 +- tools/python/xen/web/defer.py | 3 - tools/python/xen/web/httpserver.py | 37 +-- tools/python/xen/web/static.py | 3 +- tools/python/xen/xend/XendAsynchProtocol.py | 94 -------- tools/python/xen/xend/XendClient.py | 127 ++++------ tools/python/xen/xend/XendDomain.py | 36 +-- tools/python/xen/xend/XendDomainConfig.py | 44 ---- tools/python/xen/xend/XendProtocol.py | 40 +++- tools/python/xen/xend/XendRoot.py | 52 +++- tools/python/xen/xend/server/SrvBase.py | 2 - tools/python/xen/xend/server/SrvConsole.py | 2 +- tools/python/xen/xend/server/SrvDaemon.py | 4 +- tools/python/xen/xend/server/SrvDir.py | 3 - tools/python/xen/xend/server/SrvDmesg.py | 2 +- tools/python/xen/xend/server/SrvDomain.py | 64 +++-- tools/python/xen/xend/server/SrvDomainDir.py | 2 +- tools/python/xen/xend/server/SrvEventDir.py | 41 ---- tools/python/xen/xend/server/SrvNode.py | 2 +- tools/python/xen/xend/server/SrvRoot.py | 3 +- tools/python/xen/xend/server/SrvServer.py | 41 +++- tools/python/xen/xend/server/SrvUsbif.py | 239 ------------------- tools/python/xen/xend/server/SrvVnetDir.py | 2 +- tools/python/xen/xend/server/SrvXendLog.py | 2 +- tools/python/xen/xend/server/blkif.py | 4 +- tools/python/xen/xend/server/channel.py | 50 +++- tools/python/xen/xend/server/console.py | 4 +- tools/python/xen/xend/server/controller.py | 136 ++++++----- tools/python/xen/xend/server/netif.py | 4 +- tools/python/xen/xend/server/usbif.py | 4 +- tools/python/xen/xend/util.py | 0 33 files changed, 336 insertions(+), 722 deletions(-) delete mode 100644 tools/python/xen/web/defer.py delete mode 100644 tools/python/xen/xend/XendAsynchProtocol.py delete mode 100644 tools/python/xen/xend/XendDomainConfig.py delete mode 100644 tools/python/xen/xend/server/SrvBase.py delete mode 100644 tools/python/xen/xend/server/SrvDir.py delete mode 100644 tools/python/xen/xend/server/SrvEventDir.py delete mode 100644 tools/python/xen/xend/server/SrvUsbif.py delete mode 100644 tools/python/xen/xend/util.py diff --git a/.rootkeys b/.rootkeys index 410a16c677..2037a99828 100644 --- a/.rootkeys +++ b/.rootkeys @@ -883,7 +883,6 @@ 4267a9b1FfCUjW7m9anLERcx9lwhJg tools/python/xen/web/SrvDir.py 4267a9b1uMXIfzB6-81ZLqMCyTgJmw tools/python/xen/web/__init__.py 4267a9b1i_zVq36tt2iQejVuR6DGFw tools/python/xen/web/connection.py -4267a9b1Z2SpO9v-zEDApywETZPDwA tools/python/xen/web/defer.py 4267a9b1KzSWZwWKYrGRc9bUhow_7Q tools/python/xen/web/http.py 4267a9b1KWNZhhmZnySe_nLASwO47g tools/python/xen/web/httpserver.py 4267a9b21miObgEJLAgtLTAKRBK8uQ tools/python/xen/web/protocol.py @@ -897,13 +896,11 @@ 40c9c468Um_qc66OQeLEceIz1pgD5g tools/python/xen/xend/EventServer.py 40c9c468QJTEuk9g4qHxGpmIi70PEQ tools/python/xen/xend/PrettyPrint.py 40e15b7eeQxWE_hUPB2YTgM9fsZ1PQ tools/python/xen/xend/Vifctl.py -4151594bBq8h-bwTfEt8dbBuojMtcA tools/python/xen/xend/XendAsynchProtocol.py 40c9c4688m3eqnC8fhLu1APm36VOVA tools/python/xen/xend/XendClient.py 40c9c468t6iIKTjwuYoe-UMCikDcOQ tools/python/xen/xend/XendConsole.py 40c9c468WnXs6eOUSff23IIGI4kMfQ tools/python/xen/xend/XendDB.py 40eee3a0sPO-WUu34uHUXOC7HliDGw tools/python/xen/xend/XendDmesg.py 40c9c468fSl3H3IypyT0ppkbb0ZT9A tools/python/xen/xend/XendDomain.py -40c9c468bbKq3uC7_fuNUkiMMjArdw tools/python/xen/xend/XendDomainConfig.py 40c9c4685ykq87_n1kVUbMr9flx9fg tools/python/xen/xend/XendDomainInfo.py 40f50d99YiiaMI1fZBh1VCDFLD57qg tools/python/xen/xend/XendError.py 40ffc44eGsgTEY355E3nN4mPLZHhMQ tools/python/xen/xend/XendLogging.py @@ -915,19 +912,15 @@ 40c9c468x191zetrVlMnExfsQWHxIQ tools/python/xen/xend/__init__.py 40c9c468S2YnCEKmk4ey8XQIST7INg tools/python/xen/xend/encode.py 4266169ezWIlXSfY50n6HSoVFbosmw tools/python/xen/xend/scheduler.py -40c9c468DCpMe542varOolW1Xc68ew tools/python/xen/xend/server/SrvBase.py 40c9c468IxQabrKJSWs0aEjl-27mRQ tools/python/xen/xend/server/SrvConsole.py 40c9c4689Io5bxfbYIfRiUvsiLX0EQ tools/python/xen/xend/server/SrvConsoleDir.py 40c9c468woSmBByfeXA4o_jGf2gCgA tools/python/xen/xend/server/SrvDaemon.py -40c9c468EQZJVkCLds-OhesJVVyZbQ tools/python/xen/xend/server/SrvDir.py 40eee3a0m38EwYXfCSFIjWNwG6jx_A tools/python/xen/xend/server/SrvDmesg.py 40c9c468TyHZUq8sk0FF_vxM6Sozrg tools/python/xen/xend/server/SrvDomain.py 40c9c469WzajDjutou3X7FmL9hMf3g tools/python/xen/xend/server/SrvDomainDir.py -40c9c469-8mYEJJTAR6w_ClrJRAfwQ tools/python/xen/xend/server/SrvEventDir.py 40c9c4694eu5759Dehr4Uhakei0EMg tools/python/xen/xend/server/SrvNode.py 40c9c469TaZ83ypsrktmPSHLEZiP5w tools/python/xen/xend/server/SrvRoot.py 40c9c469W3sgDMbBJYQdz5wbQweL0Q tools/python/xen/xend/server/SrvServer.py -41ee5e8cFlODpYxhBMZqo9ZgGtcHbg tools/python/xen/xend/server/SrvUsbif.py 40c9c469aq7oXrE1Ngqf3_lBqL0RoQ tools/python/xen/xend/server/SrvVnetDir.py 4108f181GtRoD1U9TBuJXMfBbGJwdQ tools/python/xen/xend/server/SrvXendLog.py 40c9c469Y_aimoOFfUZoS-4eV8gEKg tools/python/xen/xend/server/__init__.py @@ -942,7 +935,6 @@ 4266169eI_oX3YBjwaeC0V-THBRnjg tools/python/xen/xend/server/pciif.py 41ee5e8dq9NtihbL4nWKjuSLOhXPUg tools/python/xen/xend/server/usbif.py 40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/python/xen/xend/sxp.py -4189125cL90jKSOcBJ3Vx4nWGiXXvA tools/python/xen/xend/util.py 40d05079aFRp6NQdo5wIh5Ly31c0cg tools/python/xen/xm/__init__.py 40cf2937gKQcATgXKGtNeWb1PDH5nA tools/python/xen/xm/create.py 40f552eariuUSB9TWqCPnDLz5zvxMw tools/python/xen/xm/destroy.py diff --git a/tools/python/xen/web/SrvBase.py b/tools/python/xen/web/SrvBase.py index b8671ba639..099eebc449 100644 --- a/tools/python/xen/web/SrvBase.py +++ b/tools/python/xen/web/SrvBase.py @@ -12,7 +12,6 @@ from xen.xend.XendLogging import log import resource import http import httpserver -import defer def uri_pathlist(p): """Split a path into a list. diff --git a/tools/python/xen/web/SrvDir.py b/tools/python/xen/web/SrvDir.py index 25dd721075..fb9eb14b3c 100644 --- a/tools/python/xen/web/SrvDir.py +++ b/tools/python/xen/web/SrvDir.py @@ -20,7 +20,7 @@ class SrvConstructor: def __init__(self, klass): """Create a constructor. It is assumed that the class - should be imported as 'import klass from klass'. + should be imported as 'from xen.xend.server.klass import klass'. klass name of its class """ diff --git a/tools/python/xen/web/defer.py b/tools/python/xen/web/defer.py deleted file mode 100644 index c5f1071b72..0000000000 --- a/tools/python/xen/web/defer.py +++ /dev/null @@ -1,3 +0,0 @@ - -class Deferred: - pass diff --git a/tools/python/xen/web/httpserver.py b/tools/python/xen/web/httpserver.py index 248c4ac528..265a75c32d 100644 --- a/tools/python/xen/web/httpserver.py +++ b/tools/python/xen/web/httpserver.py @@ -4,6 +4,8 @@ import string import socket import types from urllib import quote, unquote +import os +import os.path from xen.xend import sxp from xen.xend.Args import ArgError @@ -184,7 +186,9 @@ class HttpServerRequest(http.HttpRequest): @param val: the value """ - if isinstance(val, ThreadRequest): + if val is None: + return val + elif isinstance(val, ThreadRequest): return val elif self.useSxp(): self.setHeader("Content-Type", sxp.mime_type) @@ -316,18 +320,23 @@ class HttpServer: def getResource(self, req): return self.root.getRequestResource(req) +class UnixHttpServer(HttpServer): -def main(): - root = SrvDir() - a = root.add("a", SrvDir()) - b = root.add("b", SrvDir()) - server = HttpServer(root=root) - server.run() - -if __name__ == "__main__": - main() - - + def __init__(self, path=None, root=None): + HttpServer.__init__(self, interface='localhost', root=root) + self.path = path - - + def bind(self): + pathdir = os.path.dirname(self.path) + if not os.path.exists(pathdir): + os.makedirs(pathdir) + else: + try: + os.unlink(self.path) + except SystemExit: + raise + except Exception, ex: + pass + self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + #self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.socket.bind(self.path) diff --git a/tools/python/xen/web/static.py b/tools/python/xen/web/static.py index 3bed394e77..430be6cf0d 100644 --- a/tools/python/xen/web/static.py +++ b/tools/python/xen/web/static.py @@ -24,7 +24,7 @@ class File(Resource): if self.type: req.setHeader('Content-Type', self.type) if self.encoding: - rew.setHeader('Content-Encoding', self.encoding) + req.setHeader('Content-Encoding', self.encoding) req.setHeader('Content-Length', self.getFileSize()) try: io = file(self.filename, "r") @@ -40,7 +40,6 @@ class File(Resource): io.close() except: pass - return '' diff --git a/tools/python/xen/xend/XendAsynchProtocol.py b/tools/python/xen/xend/XendAsynchProtocol.py deleted file mode 100644 index 6afaf14285..0000000000 --- a/tools/python/xen/xend/XendAsynchProtocol.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -from twisted.protocols import http -from twisted.internet.protocol import ClientCreator -from twisted.internet.defer import Deferred -from twisted.internet import reactor - -from XendProtocol import XendClientProtocol, XendRequest - -class AsynchXendClient(http.HTTPClient): - """A subclass of twisted's HTTPClient to deal with a connection to xend. - Makes the request when connected, and delegates handling responses etc. - to its protocol (usually an AsynchXendClientProtocol instance). - """ - def __init__(self, protocol, request): - self.protocol = protocol - self.request = request - - def connectionMade(self): - request = self.request - url = self.request.url - self.sendCommand(request.method, url.fullpath()) - self.sendHeader('Host', url.location()) - for (k, v) in request.headers.items(): - self.sendHeader(k, v) - if request.data: - self.sendHeader('Content-Length', len(request.data)) - self.endHeaders() - if request.data: - self.transport.write(request.data) - - def handleStatus(self, version, status, message): - return self.protocol.handleStatus(version, status, message) - - def handleHeader(self, key, val): - return self.protocol.handleHeader(key, val) - - def handleResponse(self, data): - return self.protocol.handleResponse(data) - -class AsynchXendClientProtocol(XendClientProtocol): - """An asynchronous xend client. Uses twisted to connect to xend - and make the request. It does not block waiting for the result, - but sets up a deferred that is called when the result becomes available. - - Uses AsynchXendClient to manage the connection. - """ - def __init__(self): - self.err = None - self.headers = {} - - def xendRequest(self, url, method, args=None): - """Make a request to xend. The returned deferred is called when - the result is available. - - @param url: xend request url - @param method: http method: POST or GET - @param args: request arguments (dict) - @return: deferred - """ - request = XendRequest(url, method, args) - self.deferred = Deferred() - clientCreator = ClientCreator(reactor, AsynchXendClient, self, request) - clientCreator.connectTCP(url.host, url.port) - return self.deferred - - def callErrback(self, err): - if not self.deferred.called: - self.err = err - self.deferred.errback(err) - return err - - def callCallback(self, val): - if not self.deferred.called: - self.deferred.callback(val) - return val - - def handleException(self, err): - return self.callErrback(err) - - def handleHeader(self, key, val): - self.headers[key.lower()] = val - - def getHeader(self, key): - return self.headers.get(key.lower()) - - def handleResponse(self, data): - if self.err: return self.err - val = XendClientProtocol.handleResponse(self, data) - if isinstance(val, Exception): - self.callErrback(val) - else: - self.callCallback(val) - return val diff --git a/tools/python/xen/xend/XendClient.py b/tools/python/xen/xend/XendClient.py index e25bababf5..6b29f21e7b 100644 --- a/tools/python/xen/xend/XendClient.py +++ b/tools/python/xen/xend/XendClient.py @@ -2,7 +2,7 @@ # Copyright (C) 2004 Mike Wray """Client API for the HTTP interface on xend. Callable as a script - see main(). -Supports synchronous or asynchronous connection to xend. +Supports inet or unix connection to xend. This API is the 'control-plane' for xend. The 'data-plane' is done separately. For example, consoles @@ -15,7 +15,9 @@ import types import sxp import PrettyPrint -from XendProtocol import XendClientProtocol, SynchXendClientProtocol, XendError +from XendProtocol import HttpXendClientProtocol, \ + UnixXendClientProtocol, \ + XendError DEBUG = 0 @@ -32,15 +34,6 @@ def fileof(val): return val raise XendError('cannot convert value') -# todo: need to sort of what urls/paths are using for objects. -# e.g. for domains at the moment return '0'. -# should probably return abs path w.r.t. server, e.g. /xend/domain/0. -# As an arg, assume abs path is obj uri, otherwise just id. - -# Function to convert to full url: Xend.uri(path), e.g. -# maps /xend/domain/0 to http://wray-m-3.hpl.hp.com:8000/xend/domain/0 -# And should accept urls for ids? - class URL: """A URL. """ @@ -115,7 +108,7 @@ class Xend: @param root: xend root path on the server """ if client is None: - client = SynchXendClientProtocol() + client = HttpXendClientProtocol() self.client = client self.bind(srv, root) @@ -162,9 +155,6 @@ class Xend: def vneturl(self, id=''): return self.url.relative('vnet/' + str(id)) - def eventurl(self, id=''): - return self.url.relative('event/' + str(id)) - def xend(self): return self.xendGet(self.url) @@ -262,34 +252,33 @@ class Xend: def xend_domain_maxmem_set(self, id, memory): return self.xendPost(self.domainurl(id), - { 'op' : 'maxmem_set', - 'memory' : memory }) + { 'op' : 'maxmem_set', + 'memory' : memory }) + + def xend_domain_mem_target_set(self, id, mem_target): + val = self.xendPost(self.domainurl(id), + {'op' : 'mem_target_set', + 'target' : mem_target }) + return val def xend_domain_vif_limit(self, id, vif, credit, period): return self.xendPost(self.domainurl(id), - { 'op' : 'vif_credit_limit', + { 'op' : 'vif_limit_set', 'vif' : vif, 'credit' : credit, 'period' : period }) - def xend_domain_vifs(self, id): + def xend_domain_devices(self, id, type): return self.xendGet(self.domainurl(id), - { 'op' : 'vifs' }) + {'op' : 'devices', + 'type' : type }) - def xend_domain_vif(self, id, vif): + def xend_domain_device(self, id, type, idx): return self.xendGet(self.domainurl(id), - { 'op' : 'vif', - 'vif' : vif }) - - def xend_domain_vbds(self, id): - return self.xendGet(self.domainurl(id), - {'op' : 'vbds'}) - - def xend_domain_vbd(self, id, vbd): - return self.xendGet(self.domainurl(id), - {'op' : 'vbd', - 'vbd' : vbd }) - + {'op' : 'device', + 'type' : type, + 'idx' : idx }) + def xend_domain_device_create(self, id, config): return self.xendPost(self.domainurl(id), {'op' : 'device_create', @@ -338,63 +327,29 @@ class Xend: return self.xendPost(self.vneturl(id), {'op' : 'delete' }) - def xend_event_inject(self, sxpr): - val = self.xendPost(self.eventurl(), - {'op' : 'inject', - 'event' : fileof(sxpr) }) - - def xend_domain_mem_target_set(self, id, mem_target): - val = self.xendPost(self.domainurl(id), - {'op' : 'mem_target_set', - 'target' : mem_target }) - return val - -def getAsynchXendClientProtocol(): - """Load AsynchXendClientProtocol on demand to avoid the cost. +def getHttpServer(srv=None): + """Create and return a xend client. """ - global AsynchXendClientProtocol - try: - AsynchXendClientProtocol - except: - from XendAsynchProtocol import AsynchXendClientProtocol - return AsynchXendClientProtocol + return Xend(srv=srv, client=XendClientProtocol()) -def getAsynchServer(): - """Load AsynchXendClientProtocol and create an asynch xend client. - - @return asynch Xend +def getUnixServer(srv=None): + """Create and return a unix-domain xend client. """ - getAsynchXendClientProtocol() - return Xend(AsynchXendClientProtocol()) + return Xend(client=UnixXendClientProtocol(srv)) -def xendmain(srv, asynch, fn, args): - if asynch: - getAsynchXendClientProtocol() - client = AsynchXendClientProtocol() +def xendmain(srv, fn, args, unix=False): + if unix: + xend = getUnixServer(srv) else: - client = None - xend = Xend(srv=srv, client=client) + xend = getHttpServer(srv) xend.rc = 0 try: v = getattr(xend, fn)(*args) + PrettyPrint.prettyprint(v) + return 0 except XendError, err: print 'ERROR:', err return 1 - if asynch: - def cbok(val): - PrettyPrint.prettyprint(val) - reactor.stop() - def cberr(err): - print 'ERROR:', err - xend.rc = 1 - reactor.stop() - v.addCallback(cbok) - v.addErrback(cberr) - reactor.run() - return xend.rc - else: - PrettyPrint.prettyprint(v) - return 0 def main(argv): """Call an API function: @@ -411,16 +366,16 @@ python XendClient.py domain 0 """ global DEBUG from getopt import getopt - short_options = 'x:ad' - long_options = ['xend=', 'asynch', 'debug'] + short_options = 'x:au:d' + long_options = ['xend=', 'unix=', 'debug'] (options, args) = getopt(argv[1:], short_options, long_options) srv = None - asynch = 0 + unix = 1 for k, v in options: if k in ['-x', '--xend']: srv = v - elif k in ['-a', '--asynch']: - asynch = 1 + elif k in ['-u', '--unix']: + unix = int(v) elif k in ['-d', '--debug']: DEBUG = 1 if len(args): @@ -431,9 +386,9 @@ python XendClient.py domain 0 args = [] if not fn.startswith('xend'): fn = 'xend_' + fn - sys.exit(xendmain(srv, asynch, fn, args)) + sys.exit(xendmain(srv, fn, args, unix=unix)) if __name__ == "__main__": main(sys.argv) else: - server = Xend() + server = getUnixServer() diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 334f2f45f6..b94d4e5264 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -778,7 +778,7 @@ class XendDomain: dominfo = self.domain_lookup(id) return dominfo.getDeviceByIndex(type, idx) - def domain_vif_credit_limit(self, id, vif, credit, period): + def domain_vif_limit_set(self, id, vif, credit, period): """Limit the vif's transmission rate """ dominfo = self.domain_lookup(id) @@ -787,40 +787,6 @@ class XendDomain: raise XendError("invalid vif") return dev.setCreditLimit(credit, period) - def domain_vif_ls(self, id): - """Get list of virtual network interface (vif) indexes for a domain. - - @param id: domain - @return: vif indexes - """ - return self.domain_devtype_ls(id, 'vif') - - def domain_vif_get(self, id, vif): - """Get a virtual network interface (vif) from a domain. - - @param id: domain - @param vif: vif index - @return: vif device object (or None) - """ - return self.domain_devtype_get(id, 'vif', vif) - - def domain_vbd_ls(self, id): - """Get list of virtual block device (vbd) indexes for a domain. - - @param id: domain - @return: vbd indexes - """ - return self.domain_devtype_ls(id, 'vbd') - - def domain_vbd_get(self, id, vbd): - """Get a virtual block device (vbd) from a domain. - - @param id: domain - @param vbd: vbd index - @return: vbd device (or None) - """ - return self.domain_devtype_get(id, 'vbd', vbd) - def domain_shadow_control(self, id, op): """Shadow page control. diff --git a/tools/python/xen/xend/XendDomainConfig.py b/tools/python/xen/xend/XendDomainConfig.py deleted file mode 100644 index 35db31ff51..0000000000 --- a/tools/python/xen/xend/XendDomainConfig.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -"""Handler for persistent domain configs. - -""" - -import sxp -import XendDB -import XendDomain - -__all__ = [ "XendDomainConfig" ] - -class XendDomainConfig: - - dbpath = 'config' - - def __init__(self): - self.db = XendDB.XendDB(self.dbpath) - - def domain_config_ls(self, path): - return self.db.ls(path) - - def domain_config_create(self, path, sxpr): - self.db.save(path, sxpr) - pass - - def domain_config_delete(self, path): - self.db.delete(path) - - def domain_config_instance(self, path): - """Create a domain from a config. - """ - config = self.db.fetch(path) - xd = XendDomain.instance() - newdom = xd.domain_create(config) - return newdom - -def instance(): - global inst - try: - inst - except: - inst = XendDomainConfig() - return inst diff --git a/tools/python/xen/xend/XendProtocol.py b/tools/python/xen/xend/XendProtocol.py index db4de7940f..278173c8f5 100644 --- a/tools/python/xen/xend/XendProtocol.py +++ b/tools/python/xen/xend/XendProtocol.py @@ -1,5 +1,6 @@ # Copyright (C) 2004 Mike Wray +import socket import httplib import types @@ -122,12 +123,19 @@ class XendClientProtocol: """ raise NotImplementedError() -class SynchXendClientProtocol(XendClientProtocol): +class HttpXendClientProtocol(XendClientProtocol): """A synchronous xend client. This will make a request, wait for the reply and return the result. """ resp = None + request = None + + def makeConnection(self, url): + return httplib.HTTPConnection(url.location()) + + def makeRequest(self, url, method, args): + return XendRequest(url, method, args) def xendRequest(self, url, method, args=None): """Make a request to xend. @@ -136,8 +144,8 @@ class SynchXendClientProtocol(XendClientProtocol): @param method: http method: POST or GET @param args: request arguments (dict) """ - self.request = XendRequest(url, method, args) - conn = httplib.HTTPConnection(url.location()) + self.request = self.makeRequest(url, method, args) + conn = self.makeConnection(url) if DEBUG: conn.set_debuglevel(1) conn.request(method, url.fullpath(), self.request.data, self.request.headers) resp = conn.getresponse() @@ -154,3 +162,29 @@ class SynchXendClientProtocol(XendClientProtocol): def getHeader(self, key): return self.resp.getheader(key) +class UnixConnection(httplib.HTTPConnection): + """Subclass of Python library HTTPConnection that uses a unix-domain socket. + """ + + def __init__(self, path): + httplib.HTTPConnection.__init__(self, 'localhost') + self.path = path + + def connect(self): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.connect(self.path) + self.sock = sock + +class UnixXendClientProtocol(HttpXendClientProtocol): + """A synchronous xend client using a unix-domain socket. + """ + + XEND_PATH_DEFAULT = '/var/lib/xend/xend-socket' + + def __init__(self, path=None): + if path is None: + path = self.XEND_PATH_DEFAULT + self.path = path + + def makeConnection(self, url): + return UnixConnection(self.path) diff --git a/tools/python/xen/xend/XendRoot.py b/tools/python/xen/xend/XendRoot.py index c8236a4ecd..f2086735ec 100644 --- a/tools/python/xen/xend/XendRoot.py +++ b/tools/python/xen/xend/XendRoot.py @@ -15,6 +15,7 @@ import sys import EventServer from XendLogging import XendLogging +from XendError import XendError # Initial create of the event server. eserver = EventServer.instance() @@ -44,6 +45,9 @@ class XendRoot: loglevel_default = 'DEBUG' + """Default for the flag indicating whether xend should run an http server.""" + xend_http_server_default = 'no' + """Default interface address xend listens at. """ xend_address_default = '' @@ -53,7 +57,13 @@ class XendRoot: """Default port xend serves events at. """ xend_event_port_default = '8001' - """Default inteface address xend listens at for consoles.""" + """Default for the flag indicating whether xend should run a unix-domain server.""" + xend_unix_server_default = 'yes' + + """Default path the unix-domain server listens at.""" + xend_unix_path_default = '/var/lib/xend/xend-socket' + + """Default interface address xend listens at for consoles.""" console_address_default = '' """Default port xend serves consoles at. """ @@ -157,6 +167,7 @@ class XendRoot: logfile = self.get_config_value("logfile", self.logfile_default) loglevel = self.get_config_value("loglevel", self.loglevel_default) self.logging = XendLogging(logfile, level=loglevel) + self.logging.addLogStderr() def get_logging(self): """Get the XendLogging instance. @@ -218,15 +229,35 @@ class XendRoot: """ return sxp.child_value(self.config, name, val=val) + def get_config_bool(self, name, val=None): + v = self.get_config_value(name, val) + if v in ['yes', '1', 'on', 1, True]: + return True + if v in ['no', '0', 'off', 0, False]: + return False + raise XendError("invalid xend config %s: expected bool: %s" % (name, v)) + + def get_config_int(self, name, val=None): + v = self.get_config_value(name, val) + try: + return int(v) + except Exception, ex: + raise XendError("invalid xend config %s: expected int: %s" % (name, v)) + + def get_xend_http_server(self): + """Get the flag indicating whether xend should run an http server. + """ + return self.get_config_bool("xend-http-server", self.xend_http_server_default) + def get_xend_port(self): """Get the port xend listens at for its HTTP interface. """ - return int(self.get_config_value('xend-port', self.xend_port_default)) + return self.get_config_int('xend-port', self.xend_port_default) def get_xend_event_port(self): """Get the port xend listens at for connection to its event server. """ - return int(self.get_config_value('xend-event-port', self.xend_event_port_default)) + return self.get_config_int('xend-event-port', self.xend_event_port_default) def get_xend_address(self): """Get the address xend listens at for its HTTP and event ports. @@ -236,6 +267,16 @@ class XendRoot: """ return self.get_config_value('xend-address', self.xend_address_default) + def get_xend_unix_server(self): + """Get the flag indicating whether xend should run a unix-domain server. + """ + return self.get_config_bool("xend-unix-server", self.xend_unix_server_default) + + def get_xend_unix_path(self): + """Get the path the xend unix-domain server listens at. + """ + return self.get_config_value("xend-unix-path", self.xend_unix_path_default) + def get_console_address(self): """Get the address xend listens at for its console ports. This defaults to the empty string which allows all hosts to connect. @@ -247,7 +288,7 @@ class XendRoot: def get_console_port_base(self): """Get the base port number used to generate console ports for domains. """ - return int(self.get_config_value('console-port-base', self.console_port_base_default)) + return self.get_config_int('console-port-base', self.console_port_base_default) def get_block_script(self, type): return self.get_config_value('block-%s' % type, '') @@ -262,8 +303,7 @@ class XendRoot: return self.get_config_value('vif-script', 'vif-bridge') def get_vif_antispoof(self): - v = self.get_config_value('vif-antispoof', 'yes') - return v in ['yes', '1', 'on'] + return self.get_config_bool('vif-antispoof', 'yes') def instance(): """Get an instance of XendRoot. diff --git a/tools/python/xen/xend/server/SrvBase.py b/tools/python/xen/xend/server/SrvBase.py deleted file mode 100644 index 9ad1af2ef3..0000000000 --- a/tools/python/xen/xend/server/SrvBase.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (C) 2004 Mike Wray -from xen.web.SrvBase import * diff --git a/tools/python/xen/xend/server/SrvConsole.py b/tools/python/xen/xend/server/SrvConsole.py index 2db502d899..233f62b968 100644 --- a/tools/python/xen/xend/server/SrvConsole.py +++ b/tools/python/xen/xend/server/SrvConsole.py @@ -2,7 +2,7 @@ from xen.xend import sxp from xen.xend import XendConsole -from SrvDir import SrvDir +from xen.web.SrvDir import SrvDir class SrvConsole(SrvDir): """An individual console. diff --git a/tools/python/xen/xend/server/SrvDaemon.py b/tools/python/xen/xend/server/SrvDaemon.py index dcc0e14eef..7495248753 100644 --- a/tools/python/xen/xend/server/SrvDaemon.py +++ b/tools/python/xen/xend/server/SrvDaemon.py @@ -326,10 +326,10 @@ class Daemon: self.createFactories() self.listenEvent(xroot) self.listenChannels() - serverthread = SrvServer.create(bridge=1) + servers = SrvServer.create() self.daemonize() print 'running serverthread...' - serverthread.start() + servers.start() except Exception, ex: print >>sys.stderr, 'Exception starting xend:', ex if DEBUG: diff --git a/tools/python/xen/xend/server/SrvDir.py b/tools/python/xen/xend/server/SrvDir.py deleted file mode 100644 index 05694c28a9..0000000000 --- a/tools/python/xen/xend/server/SrvDir.py +++ /dev/null @@ -1,3 +0,0 @@ -# Copyright (C) 2004 Mike Wray -from xen.web.SrvBase import * -from xen.web.SrvDir import * diff --git a/tools/python/xen/xend/server/SrvDmesg.py b/tools/python/xen/xend/server/SrvDmesg.py index f9c3718add..fbf337712a 100644 --- a/tools/python/xen/xend/server/SrvDmesg.py +++ b/tools/python/xen/xend/server/SrvDmesg.py @@ -5,7 +5,7 @@ import os from xen.xend import sxp from xen.xend import XendDmesg -from SrvDir import SrvDir +from xen.web.SrvDir import SrvDir class SrvDmesg(SrvDir): """Xen Dmesg output. diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py index 27ffb0abfd..80fbd97703 100644 --- a/tools/python/xen/xend/server/SrvDomain.py +++ b/tools/python/xen/xend/server/SrvDomain.py @@ -8,7 +8,7 @@ from xen.xend import XendConsole from xen.xend import PrettyPrint from xen.xend.Args import FormFn -from SrvDir import SrvDir +from xen.web.SrvDir import SrvDir class SrvDomain(SrvDir): """Service managing a single domain. @@ -35,10 +35,6 @@ class SrvDomain(SrvDir): return val def op_pause(self, op, req): - # Pause doesn't need a thread, but request one for testing. - return req.threadRequest(self.do_pause, op, req) - - def do_pause(self, op, req): val = self.xd.domain_pause(self.dom.name) return val @@ -113,6 +109,31 @@ class SrvDomain(SrvDir): ['memory', 'int']]) val = fn(req.args, {'dom': self.dom.id}) return val + + def op_mem_target_set(self, op, req): + fn = FormFn(self.xd.domain_mem_target_set, + [['dom', 'str'], + ['target', 'int']]) + val = fn(req.args, {'dom': self.dom.id}) + return val + + def op_devices(self, op, req): + fn = FormFn(self.xd.domain_devtype_ls, + [['dom', 'str'], + ['type', 'str']]) + val = fn(req.args, {'dom': self.dom.id}) + return val + + def op_device(self, op, req): + fn = FormFn(self.xd.domain_devtype_get, + [['dom', 'str'], + ['type', 'str'], + ['idx', 'int']]) + val = fn(req.args, {'dom': self.dom.id}) + if val: + return val.sxpr() + else: + raise XendError("invalid device") def op_device_create(self, op, req): fn = FormFn(self.xd.domain_device_create, @@ -145,8 +166,8 @@ class SrvDomain(SrvDir): val = fn(req.args, {'dom': self.dom.id}) return val - def op_vif_credit_limit(self, op, req): - fn = FormFn(self.xd.domain_vif_credit_limit, + def op_vif_limit_set(self, op, req): + fn = FormFn(self.xd.domain_vif_limit_set, [['dom', 'str'], ['vif', 'int'], ['credit', 'int'], @@ -154,35 +175,6 @@ class SrvDomain(SrvDir): val = fn(req.args, {'dom': self.dom.id}) return val - def op_vifs(self, op, req): - devs = self.xd.domain_vif_ls(self.dom.id) - return [ dev.sxpr() for dev in devs ] - - def op_vif(self, op, req): - fn = FormFn(self.xd.domain_vif_get, - [['dom', 'str'], - ['vif', 'str']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def op_vbds(self, op, req): - devs = self.xd.domain_vbd_ls(self.dom.id) - return [ dev.sxpr() for dev in devs ] - - def op_vbd(self, op, req): - fn = FormFn(self.xd.domain_vbd_get, - [['dom', 'str'], - ['vbd', 'str']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def op_mem_target_set(self, op, req): - fn = FormFn(self.xd.domain_mem_target_set, - [['dom', 'str'], - ['target', 'int']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - def render_POST(self, req): return self.perform(req) diff --git a/tools/python/xen/xend/server/SrvDomainDir.py b/tools/python/xen/xend/server/SrvDomainDir.py index e007baf4d5..6969d87e05 100644 --- a/tools/python/xen/xend/server/SrvDomainDir.py +++ b/tools/python/xen/xend/server/SrvDomainDir.py @@ -11,7 +11,7 @@ from xen.xend.Args import FormFn from xen.xend.XendError import XendError from xen.xend.XendLogging import log -from SrvDir import SrvDir +from xen.web.SrvDir import SrvDir from SrvDomain import SrvDomain class SrvDomainDir(SrvDir): diff --git a/tools/python/xen/xend/server/SrvEventDir.py b/tools/python/xen/xend/server/SrvEventDir.py deleted file mode 100644 index 02871a426a..0000000000 --- a/tools/python/xen/xend/server/SrvEventDir.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -from xen.xend import sxp -from xen.xend import EventServer -from SrvDir import SrvDir - -class SrvEventDir(SrvDir): - """Event directory. - """ - - def __init__(self): - SrvDir.__init__(self) - self.eserver = EventServer.instance() - - def op_inject(self, op, req): - eventstring = req.args.get('event') - pin = sxp.Parser() - pin.input(eventstring) - pin.input_eof() - sxpr = pin.get_val() - self.eserver.inject(sxp.name(sxpr), sxpr) - if req.use_sxp: - sxp.name(sxpr) - else: - return '' + eventstring + '' - - def render_POST(self, req): - return self.perform(req) - - def form(self, req): - action = req.prePathURL() - req.write('
' - % action) - req.write('') - req.write('Event
') - req.write('
') - req.write('
' - % action) - req.write('') - req.write('Event file
') - req.write('
') diff --git a/tools/python/xen/xend/server/SrvNode.py b/tools/python/xen/xend/server/SrvNode.py index 85a8ba4719..6768e9b5fe 100644 --- a/tools/python/xen/xend/server/SrvNode.py +++ b/tools/python/xen/xend/server/SrvNode.py @@ -2,7 +2,7 @@ import os -from SrvDir import SrvDir +from xen.web.SrvDir import SrvDir from xen.xend import sxp from xen.xend import XendNode from xen.xend.Args import FormFn diff --git a/tools/python/xen/xend/server/SrvRoot.py b/tools/python/xen/xend/server/SrvRoot.py index d6d6cb0ae4..84ef008118 100644 --- a/tools/python/xen/xend/server/SrvRoot.py +++ b/tools/python/xen/xend/server/SrvRoot.py @@ -2,7 +2,7 @@ from xen.xend import XendRoot xroot = XendRoot.instance() -from SrvDir import SrvDir +from xen.web.SrvDir import SrvDir class SrvRoot(SrvDir): """The root of the xend server. @@ -16,7 +16,6 @@ class SrvRoot(SrvDir): ('node', 'SrvNode' ), ('domain', 'SrvDomainDir' ), ('console', 'SrvConsoleDir' ), - ('event', 'SrvEventDir' ), ('vnet', 'SrvVnetDir' ), ] diff --git a/tools/python/xen/xend/server/SrvServer.py b/tools/python/xen/xend/server/SrvServer.py index 43edbe3126..bed1d31948 100644 --- a/tools/python/xen/xend/server/SrvServer.py +++ b/tools/python/xen/xend/server/SrvServer.py @@ -27,23 +27,38 @@ from threading import Thread -from xen.web.httpserver import HttpServer +from xen.web.httpserver import HttpServer, UnixHttpServer -from xen.xend import XendRoot -xroot = XendRoot.instance() +from xen.xend import XendRoot; xroot = XendRoot.instance() from xen.xend import Vifctl +from xen.web.SrvDir import SrvDir + from SrvRoot import SrvRoot -from SrvDir import SrvDir -def create(port=None, interface=None, bridge=0): - if port is None: - port = xroot.get_xend_port() - if interface is None: - interface = xroot.get_xend_address() - if bridge: +class XendServers: + + def __init__(self): + self.servers = [] + + def add(self, server): + self.servers.append(server) + + def start(self): Vifctl.network('start') + for server in self.servers: + thread = Thread(target=server.run) + thread.start() + +def create(): root = SrvDir() root.putChild('xend', SrvRoot()) - server = HttpServer(root=root, interface=interface, port=port) - thread = Thread(name="XendHttpServer", target=server.run) - return thread + servers = XendServers() + if xroot.get_xend_http_server(): + port = xroot.get_xend_port() + interface = xroot.get_xend_address() + servers.add(HttpServer(root=root, interface=interface, port=port)) + if xroot.get_xend_unix_server(): + path = xroot.get_xend_unix_path() + print 'unix path=', path + servers.add(UnixHttpServer(path=path, root=root)) + return servers diff --git a/tools/python/xen/xend/server/SrvUsbif.py b/tools/python/xen/xend/server/SrvUsbif.py deleted file mode 100644 index 5ca73c9652..0000000000 --- a/tools/python/xen/xend/server/SrvUsbif.py +++ /dev/null @@ -1,239 +0,0 @@ -# Copyright (C) 2004 Mike Wray - -from xen.web import http - -from xen.xend import sxp -from xen.xend import XendDomain -from xen.xend import XendConsole -from xen.xend import PrettyPrint -from xen.xend.Args import FormFn - -from SrvDir import SrvDir - -class SrvDomain(SrvDir): - """Service managing a single domain. - """ - - def __init__(self, dom): - SrvDir.__init__(self) - self.dom = dom - self.xd = XendDomain.instance() - self.xconsole = XendConsole.instance() - - def op_configure(self, op, req): - """Configure an existing domain. - Configure is unusual in that it requires a domain id, - not a domain name. - """ - fn = FormFn(self.xd.domain_configure, - [['dom', 'int'], - ['config', 'sxpr']]) - deferred = fn(req.args, {'dom': self.dom.dom}) - deferred.addErrback(self._op_configure_err, req) - return deferred - - def _op_configure_err(self, err, req): - req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err)) - return str(err) - - def op_unpause(self, op, req): - val = self.xd.domain_unpause(self.dom.name) - return val - - def op_pause(self, op, req): - val = self.xd.domain_pause(self.dom.name) - return val - - def op_shutdown(self, op, req): - fn = FormFn(self.xd.domain_shutdown, - [['dom', 'str'], - ['reason', 'str']]) - val = fn(req.args, {'dom': self.dom.id}) - req.setResponseCode(http.ACCEPTED) - req.setHeader("Location", "%s/.." % req.prePathURL()) - return val - - def op_destroy(self, op, req): - fn = FormFn(self.xd.domain_destroy, - [['dom', 'str'], - ['reason', 'str']]) - val = fn(req.args, {'dom': self.dom.id}) - req.setHeader("Location", "%s/.." % req.prePathURL()) - return val - - def op_save(self, op, req): - fn = FormFn(self.xd.domain_save, - [['dom', 'str'], - ['file', 'str']]) - deferred = fn(req.args, {'dom': self.dom.id}) - deferred.addCallback(self._op_save_cb, req) - deferred.addErrback(self._op_save_err, req) - return deferred - - def _op_save_cb(self, val, req): - return 0 - - def _op_save_err(self, err, req): - req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err)) - return str(err) - - def op_migrate(self, op, req): - fn = FormFn(self.xd.domain_migrate, - [['dom', 'str'], - ['destination', 'str'], - ['live', 'int']]) - deferred = fn(req.args, {'dom': self.dom.id}) - print 'op_migrate>', deferred - deferred.addCallback(self._op_migrate_cb, req) - deferred.addErrback(self._op_migrate_err, req) - return deferred - - def _op_migrate_cb(self, info, req): - print '_op_migrate_cb>', info, req - #req.setResponseCode(http.ACCEPTED) - host = info.dst_host - port = info.dst_port - dom = info.dst_dom - url = "http://%s:%d/xend/domain/%d" % (host, port, dom) - req.setHeader("Location", url) - print '_op_migrate_cb> url=', url - return url - - def _op_migrate_err(self, err, req): - print '_op_migrate_err>', err, req - req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err)) - return str(err) - - def op_pincpu(self, op, req): - fn = FormFn(self.xd.domain_pincpu, - [['dom', 'str'], - ['cpu', 'int']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def op_cpu_bvt_set(self, op, req): - fn = FormFn(self.xd.domain_cpu_bvt_set, - [['dom', 'str'], - ['mcuadv', 'int'], - ['warpback', 'int'], - ['warpvalue', 'int'], - ['warpl', 'long'], - ['warpu', 'long']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def op_cpu_fbvt_set(self, op, req): - fn = FormFn(self.xd.domain_cpu_fbvt_set, - [['dom', 'str'], - ['mcuadv', 'int'], - ['warp', 'int'], - ['warpl', 'int'], - ['warpu', 'int']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def op_maxmem_set(self, op, req): - fn = FormFn(self.xd.domain_maxmem_set, - [['dom', 'str'], - ['memory', 'int']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def op_device_create(self, op, req): - fn = FormFn(self.xd.domain_device_create, - [['dom', 'str'], - ['config', 'sxpr']]) - d = fn(req.args, {'dom': self.dom.id}) - return d - - def op_device_destroy(self, op, req): - fn = FormFn(self.xd.domain_device_destroy, - [['dom', 'str'], - ['type', 'str'], - ['idx', 'str']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def op_vifs(self, op, req): - devs = self.xd.domain_vif_ls(self.dom.id) - return [ dev.sxpr() for dev in devs ] - - def op_vif(self, op, req): - fn = FormFn(self.xd.domain_vif_get, - [['dom', 'str'], - ['vif', 'str']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def op_vbds(self, op, req): - devs = self.xd.domain_vbd_ls(self.dom.id) - return [ dev.sxpr() for dev in devs ] - - def op_vbd(self, op, req): - fn = FormFn(self.xd.domain_vbd_get, - [['dom', 'str'], - ['vbd', 'str']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def render_POST(self, req): - return self.perform(req) - - def render_GET(self, req): - op = req.args.get('op') - if op and op[0] in ['vifs', 'vif', 'vbds', 'vbd']: - return self.perform(req) - if self.use_sxp(req): - req.setHeader("Content-Type", sxp.mime_type) - sxp.show(self.dom.sxpr(), out=req) - else: - req.write('') - self.print_path(req) - #self.ls() - req.write('

%s

' % self.dom) - if self.dom.console: - cinfo = self.dom.console - cid = str(cinfo.console_port) - #todo: Local xref: need to know server prefix. - req.write('

Console %s

' - % (cid, cid)) - req.write('

Connect to console

' - % cinfo.uri()) - if self.dom.config: - req.write("
")
-                PrettyPrint.prettyprint(self.dom.config, out=req)
-                req.write("
") - self.form(req) - req.write('') - return '' - - def form(self, req): - url = req.prePathURL() - req.write('
' % url) - req.write('') - req.write('') - req.write('
') - - req.write('
' % url) - req.write('') - req.write('Halt') - req.write('Reboot') - req.write('
') - - req.write('
' % url) - req.write('') - req.write('Poweroff') - req.write('Halt') - req.write('Reboot') - req.write('
') - - req.write('
' % url) - req.write('
') - req.write(' To file: ') - req.write('
') - - req.write('
' % url) - req.write('
') - req.write(' To host: ') - req.write('Live') - req.write('
') diff --git a/tools/python/xen/xend/server/SrvVnetDir.py b/tools/python/xen/xend/server/SrvVnetDir.py index 67f7706f44..bc5b583b42 100644 --- a/tools/python/xen/xend/server/SrvVnetDir.py +++ b/tools/python/xen/xend/server/SrvVnetDir.py @@ -5,7 +5,7 @@ from xen.xend.Args import FormFn from xen.xend import PrettyPrint from xen.xend import XendVnet -from SrvDir import SrvDir +from xen.web.SrvDir import SrvDir class SrvVnet(SrvDir): diff --git a/tools/python/xen/xend/server/SrvXendLog.py b/tools/python/xen/xend/server/SrvXendLog.py index efb28eb492..9b8a7dc0e8 100644 --- a/tools/python/xen/xend/server/SrvXendLog.py +++ b/tools/python/xen/xend/server/SrvXendLog.py @@ -4,7 +4,7 @@ from xen.web import static from xen.xend import XendRoot -from SrvDir import SrvDir +from xen.web.SrvDir import SrvDir class SrvXendLog(SrvDir): """Xend log. diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py index 18e94e336a..10ce6c9eac 100755 --- a/tools/python/xen/xend/server/blkif.py +++ b/tools/python/xen/xend/server/blkif.py @@ -425,10 +425,10 @@ class BlkifController(DevController): for a domain. """ - def __init__(self, dctype, vm, recreate=False): + def __init__(self, vm, recreate=False): """Create a block device controller. """ - DevController.__init__(self, dctype, vm, recreate=recreate) + DevController.__init__(self, vm, recreate=recreate) self.backends = {} self.backendId = 0 self.rcvr = None diff --git a/tools/python/xen/xend/server/channel.py b/tools/python/xen/xend/server/channel.py index 3373f50490..d60c206382 100755 --- a/tools/python/xen/xend/server/channel.py +++ b/tools/python/xen/xend/server/channel.py @@ -66,6 +66,8 @@ class ChannelFactory: def __init__(self): """Constructor - do not use. Use the channelFactory function.""" self.notifier = xu.notifier() + # Register interest in all virqs. + # Unfortunately virqs do not seem to be delivered. self.bind_virq(VIRQ_MISDIRECT) self.bind_virq(VIRQ_TIMER) self.bind_virq(VIRQ_DEBUG) @@ -97,6 +99,7 @@ class ChannelFactory: def main(self): """Main routine for the thread. + Reads the notifier and dispatches to channels. """ while True: if self.thread == None: return @@ -224,18 +227,23 @@ def channelFactory(): return inst class Channel: + """Chanel to a domain. + Maintains a list of device handlers to dispatch requests to, based + on the request type. + """ def __init__(self, factory, dom, local_port, remote_port): self.factory = factory self.dom = int(dom) - # Registered devices. + # Registered device handlers. self.devs = [] - # Devices indexed by the message types they handle. + # Handlers indexed by the message types they handle. self.devs_by_type = {} self.port = self.factory.createPort(self.dom, local_port=local_port, remote_port=remote_port) self.closed = False + # Queue of waiters for responses to requests. self.queue = ResponseQueue(self) # Make sure the port will deliver all the messages. self.port.register(TYPE_WILDCARD) @@ -298,11 +306,11 @@ class Channel: def registerDevice(self, types, dev): - """Register a device controller. + """Register a device message handler. - @param types: message types the controller handles + @param types: message types handled @type types: array of ints - @param dev: device controller + @param dev: device handler """ if self.closed: return self.devs.append(dev) @@ -310,9 +318,9 @@ class Channel: self.devs_by_type[ty] = dev def deregisterDevice(self, dev): - """Remove the registration for a device controller. + """Remove the registration for a device handler. - @param dev: device controller + @param dev: device handler """ if dev in self.devs: self.devs.remove(dev) @@ -321,16 +329,20 @@ class Channel: del self.devs_by_type[ty] def getDevice(self, type): - """Get the device controller handling a message type. + """Get the handler for a message type. @param type: message type @type type: int @return: controller or None - @rtype: device controller + @rtype: device handler """ return self.devs_by_type.get(type) def requestReceived(self, msg): + """A request has been received on the channel. + Disptach it to the device handlers. + Called from the channel factory thread. + """ if DEBUG: print 'Channel>requestReceived>', self, printMsg(msg) @@ -340,7 +352,7 @@ class Channel: if dev: responded = dev.requestReceived(msg, ty, subty) elif DEBUG: - print "Channel>requestReceived> No device", self, + print "Channel>requestReceived> No device handler", self, printMsg(msg) else: pass @@ -348,6 +360,8 @@ class Channel: self.writeResponse(msg) def writeRequest(self, msg): + """Write a request to the channel. + """ if DEBUG: print 'Channel>writeRequest>', self, printMsg(msg, all=True) @@ -356,6 +370,8 @@ class Channel: return 1 def writeResponse(self, msg): + """Write a response to the channel. + """ if DEBUG: print 'Channel>writeResponse>', self, printMsg(msg, all=True) @@ -364,6 +380,9 @@ class Channel: return 1 def readRequest(self): + """Read a request from the channel. + Called internally. + """ if self.closed: val = None else: @@ -371,6 +390,9 @@ class Channel: return val def readResponse(self): + """Read a response from the channel. + Called internally. + """ if self.closed: val = None else: @@ -399,6 +421,10 @@ class Channel: return self.queue.call(msg, timeout) def responseReceived(self, msg): + """A response has been received, look for a waiter to + give it to. + Called internally. + """ if DEBUG: print 'Channel>responseReceived>', self, printMsg(msg) @@ -407,7 +433,6 @@ class Channel: def virq(self): self.factory.virq() - class Response: """Entry in the response queue. Used to signal a response to a message. @@ -463,7 +488,8 @@ class ResponseQueue: return r def response(self, mid, msg): - """Process a response. + """Process a response - signals any waiter that a response + has arrived. """ try: self.lock.acquire() diff --git a/tools/python/xen/xend/server/console.py b/tools/python/xen/xend/server/console.py index 339366fa6e..ac63703f21 100755 --- a/tools/python/xen/xend/server/console.py +++ b/tools/python/xen/xend/server/console.py @@ -326,8 +326,8 @@ class ConsoleController(DevController): """Device controller for all the consoles for a domain. """ - def __init__(self, dctype, vm, recreate=False): - DevController.__init__(self, dctype, vm, recreate=recreate) + def __init__(self, vm, recreate=False): + DevController.__init__(self, vm, recreate=recreate) self.rcvr = None def initController(self, recreate=False, reboot=False): diff --git a/tools/python/xen/xend/server/controller.py b/tools/python/xen/xend/server/controller.py index 9343c8b132..9205b2778e 100755 --- a/tools/python/xen/xend/server/controller.py +++ b/tools/python/xen/xend/server/controller.py @@ -9,7 +9,7 @@ from messages import msgTypeName, printMsg, getMessageType DEBUG = 0 class CtrlMsgRcvr: - """Dispatcher class for messages on a control channel. + """Utility class to dispatch messages on a control channel. Once I{registerChannel} has been called, our message types are registered with the channel. The channel will call I{requestReceived} when a request arrives if it has one of our message types. @@ -105,65 +105,32 @@ class CtrlMsgRcvr: if self.channel: self.channel.deregisterDevice(self) -class DevControllerType: - """Abstract class for device controller types. - """ - - def __init__(self, type): - self.type = type - - def getType(self): - """Get the device controller type name. - """ - return self.type - - def createDevController(self, vm, recreate=False): - """Create a device controller for a domain. - Must be implemented in subclass. - """ - raise NotImplementedError() - -class SimpleDevControllerType(DevControllerType): - """Device controller type that simply wraps a controller - class and uses its constructor to create instances. - """ - - def __init__(self, type, devControllerClass): - DevControllerType.__init__(self, type) - self.devControllerClass = devControllerClass - - def createDevController(self, vm, recreate=False): - """Create a device controller for a domain. - """ - ctrl = self.devControllerClass(self, vm, recreate=recreate) - ctrl.initController(recreate=recreate) - return ctrl - class DevControllerTable: - """Table of device controller types, indexed by type name. + """Table of device controller classes, indexed by type name. """ def __init__(self): - self.controllerTypes = {} + self.controllerClasses = {} - def getDevControllerType(self, type): - return self.controllerTypes.get(type) + def getDevControllerClass(self, type): + return self.controllerClasses.get(type) - def addDevControllerType(self, dctype): - self.controllerTypes[dctype.getType()] = dctype - return dctype + def addDevControllerClass(self, klass): + self.controllerClasses[klass.getType()] = klass - def delDevControllerType(self, type): - if type in self.controllerTypes: - del self.controllerTypes[type] + def delDevControllerClass(self, type): + if type in self.controllerClasses: + del self.controllerClasses[type] def createDevController(self, type, vm, recreate=False): - dctype = self.getDevControllerType(type) - if not dctype: + klass = self.getDevControllerClass(type) + if not klass: raise XendError("unknown device type: " + type) - return dctype.createDevController(vm, recreate=recreate) + return klass.createDevController(vm, recreate=recreate) def getDevControllerTable(): + """Singleton constructor for the controller table. + """ global devControllerTable try: devControllerTable @@ -171,12 +138,11 @@ def getDevControllerTable(): devControllerTable = DevControllerTable() return devControllerTable -def addDevControllerType(dctype): - return getDevControllerTable().addDevControllerType(dctype) - def addDevControllerClass(name, klass): - ty = SimpleDevControllerType(name, klass) - return addDevControllerType(ty) + """Add a device controller class to the controller table. + """ + klass.name = name + getDevControllerTable().addDevControllerClass(klass) def createDevController(name, vm, recreate=False): return getDevControllerTable().createDevController(name, vm, recreate=recreate) @@ -189,17 +155,29 @@ class DevController: """ - def __init__(self, dctype, vm, recreate=False): - self.dctype = dctype + name = None + + def createDevController(klass, vm, recreate=False): + """Class method to create a dev controller. + """ + ctrl = klass(vm, recreate=recreate) + ctrl.initController(recreate=recreate) + return ctrl + + createDevController = classmethod(createDevController) + + def getType(klass): + return klass.name + + getType = classmethod(getType) + + def __init__(self, vm, recreate=False): self.destroyed = False self.vm = vm self.deviceId = 0 self.devices = {} self.device_order = [] - def getType(self): - return self.dctype.getType() - def getDevControllerType(self): return self.dctype @@ -222,6 +200,14 @@ class DevController: # Redefinitions must have the same arguments. def initController(self, recreate=False, reboot=False): + """Initialise the controller. Called when the controller is + first created, and again after the domain is rebooted (with reboot True). + If called with recreate True (and reboot False) the controller is being + recreated after a xend restart. + + As this can be a re-init (after reboot) any controller state should + be reset. For example the destroyed flag. + """ self.destroyed = False if reboot: self.rebootDevices() @@ -229,12 +215,19 @@ class DevController: def newDevice(self, id, config, recreate=False): """Create a device with the given config. Must be defined in subclass. + Called with recreate True when the device is being recreated after a + xend restart. @return device """ raise NotImplementedError() def createDevice(self, config, recreate=False, change=False): + """Create a device and attach to its front- and back-ends. + If recreate is true the device is being recreated after a xend restart. + If change is true the device is a change to an existing domain, + i.e. it is being added at runtime rather than when the domain is created. + """ dev = self.newDevice(self.nextDeviceId(), config, recreate=recreate) dev.init(recreate=recreate) self.addDevice(dev) @@ -252,7 +245,12 @@ class DevController: def destroyDevice(self, id, change=False, reboot=False): """Destroy a device. - May be defined in subclass.""" + May be defined in subclass. + + If reboot is true the device is being destroyed for a domain reboot. + + The device is not deleted, since it may be recreated later. + """ dev = self.getDevice(id) if not dev: raise XendError("invalid device id: " + id) @@ -260,12 +258,18 @@ class DevController: return dev def deleteDevice(self, id, change=True): + """Destroy a device and delete it. + Normally called to remove a device from a domain at runtime. + """ dev = self.destroyDevice(id, change=change) self.removeDevice(dev) def destroyController(self, reboot=False): """Destroy all devices and clean up. - May be defined in subclass.""" + May be defined in subclass. + If reboot is true the controller is being destroyed for a domain reboot. + Called at domain shutdown. + """ self.destroyed = True self.destroyDevices(reboot=reboot) @@ -394,6 +398,13 @@ class Dev: """Initialization. Called on initial create (when reboot is False) and on reboot (when reboot is True). When xend is restarting is called with recreate True. Define in subclass if needed. + + Device instance variables must be defined in the class constructor, + but given null or default values. The real values should be initialised + in this method. This allows devices to be re-initialised. + + Since this can be called to re-initialise a device any state flags + should be reset. """ self.destroyed = False @@ -404,7 +415,7 @@ class Dev: pass def reboot(self): - """Reconnect device when the domain is rebooted. + """Reconnect the device when the domain is rebooted. """ self.init(reboot=True) self.attach() @@ -435,6 +446,9 @@ class Dev: If change is True notify destruction (runtime change). If reboot is True the device is being destroyed for a reboot. Redefine in subclass if needed. + + Called at domain shutdown and when a device is deleted from + a running domain (with change True). """ self.destroyed = True pass diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py index 8c61994caf..5e3d0d7446 100755 --- a/tools/python/xen/xend/server/netif.py +++ b/tools/python/xen/xend/server/netif.py @@ -376,8 +376,8 @@ class NetifController(DevController): """Network interface controller. Handles all network devices for a domain. """ - def __init__(self, dctype, vm, recreate=False): - DevController.__init__(self, dctype, vm, recreate=recreate) + def __init__(self, vm, recreate=False): + DevController.__init__(self, vm, recreate=recreate) self.channel = None self.rcvr = None self.channel = None diff --git a/tools/python/xen/xend/server/usbif.py b/tools/python/xen/xend/server/usbif.py index e529d51761..0c1dd6f638 100644 --- a/tools/python/xen/xend/server/usbif.py +++ b/tools/python/xen/xend/server/usbif.py @@ -240,10 +240,10 @@ class UsbifController(DevController): for a domain. """ - def __init__(self, dctype, vm, recreate=False): + def __init__(self, vm, recreate=False): """Create a USB device controller. """ - DevController.__init__(self, dctype, vm, recreate=recreate) + DevController.__init__(self, vm, recreate=recreate) self.backends = {} self.backendId = 0 self.rcvr = None diff --git a/tools/python/xen/xend/util.py b/tools/python/xen/xend/util.py deleted file mode 100644 index e69de29bb2..0000000000 -- 2.30.2